<?php

// +----------------------------------------------------------------------

// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]

// +----------------------------------------------------------------------

// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved.

// +----------------------------------------------------------------------

// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )

// +----------------------------------------------------------------------

// | Author: liu21st <liu21st@gmail.com>

// +----------------------------------------------------------------------

namespace Think\Template;

/**

 * ThinkPHP标签库TagLib解析基类

 */

class TagLib {



    /**

     * 标签库定义XML文件

     * @var string

     * @access protected

     */

    protected $xml      = '';

    protected $tags     = array();// 标签定义

    /**

     * 标签库名称

     * @var string

     * @access protected

     */

    protected $tagLib   ='';



    /**

     * 标签库标签列表

     * @var string

     * @access protected

     */

    protected $tagList  = array();



    /**

     * 标签库分析数组

     * @var string

     * @access protected

     */

    protected $parse    = array();



    /**

     * 标签库是否有效

     * @var string

     * @access protected

     */

    protected $valid    = false;



    /**

     * 当前模板对象

     * @var object

     * @access protected

     */

    protected $tpl;



    protected $comparison = array(' nheq '=>' !== ',' heq '=>' === ',' neq '=>' != ',' eq '=>' == ',' egt '=>' >= ',' gt '=>' > ',' elt '=>' <= ',' lt '=>' < ');



    /**

     * 架构函数

     * @access public

     */

    public function __construct() {

        $this->tagLib  = strtolower(substr(get_class($this),6));

        $this->tpl     = \Think\Think::instance('Think\\Template');

    }



    /**

     * TagLib标签属性分析 返回标签属性数组

     * @access public

     * @param string $tagStr 标签内容

     * @return array

     */

    public function parseXmlAttr($attr,$tag) {

        //XML解析安全过滤

        $attr   =   str_replace('&','___', $attr);

        $xml    =   '<tpl><tag '.$attr.' /></tpl>';

        $xml    =   simplexml_load_string($xml);

        if(!$xml) {

            E(L('_XML_TAG_ERROR_').' : '.$attr);

        }

        $xml    =   (array)($xml->tag->attributes());

        if(isset($xml['@attributes'])){

            $array  =   array_change_key_case($xml['@attributes']);

            if($array) {

                $tag    =   strtolower($tag);

                if(!isset($this->tags[$tag])){

                    // 检测是否存在别名定义

                    foreach($this->tags as $key=>$val){

                        if(isset($val['alias']) && in_array($tag,explode(',',$val['alias']))){

                            $item  =   $val;

                            break;

                        }

                    }

                }else{

                    $item  =   $this->tags[$tag];

                }            

                $attrs  = explode(',',$item['attr']);

                if(isset($item['must'])){

                    $must   =   explode(',',$item['must']);

                }else{

                    $must   =   array();

                }

                foreach($attrs as $name) {

                    if( isset($array[$name])) {

                        $array[$name] = str_replace('___','&',$array[$name]);

                    }elseif(false !== array_search($name,$must)){

                        E(L('_PARAM_ERROR_').':'.$name);

                    }

                }

                return $array;

            }

        }else{

            return array();

        }

    }



    /**

     * 解析条件表达式

     * @access public

     * @param string $condition 表达式标签内容

     * @return array

     */

    public function parseCondition($condition) {

        $condition = str_ireplace(array_keys($this->comparison),array_values($this->comparison),$condition);

        $condition = preg_replace('/\$(\w+):(\w+)\s/is','$\\1->\\2 ',$condition);

        switch(strtolower(C('TMPL_VAR_IDENTIFY'))) {

            case 'array': // 识别为数组

                $condition  =   preg_replace('/\$(\w+)\.(\w+)\s/is','$\\1["\\2"] ',$condition);

                break;

            case 'obj':  // 识别为对象

                $condition  =   preg_replace('/\$(\w+)\.(\w+)\s/is','$\\1->\\2 ',$condition);

                break;

            default:  // 自动判断数组或对象 只支持二维

                $condition  =   preg_replace('/\$(\w+)\.(\w+)\s/is','(is_array($\\1)?$\\1["\\2"]:$\\1->\\2) ',$condition);

        }

        if(false !== strpos($condition, '$Think'))

            $condition      =   preg_replace_callback('/(\$Think.*?)\s/is', array($this, 'parseThinkVar'), $condition);        

        return $condition;

    }



    /**

     * 自动识别构建变量

     * @access public

     * @param string $name 变量描述

     * @return string

     */

    public function autoBuildVar($name) {

        if('Think.' == substr($name,0,6)){

            // 特殊变量

            return $this->parseThinkVar($name);

        }elseif(strpos($name,'.')) {

            $vars = explode('.',$name);

            $var  =  array_shift($vars);

            switch(strtolower(C('TMPL_VAR_IDENTIFY'))) {

                case 'array': // 识别为数组

                    $name = '$'.$var;

                    foreach ($vars as $key=>$val){

                        if(0===strpos($val,'$')) {

                            $name .= '["{'.$val.'}"]';

                        }else{

                            $name .= '["'.$val.'"]';

                        }

                    }

                    break;

                case 'obj':  // 识别为对象

                    $name = '$'.$var;

                    foreach ($vars as $key=>$val)

                        $name .= '->'.$val;

                    break;

                default:  // 自动判断数组或对象 只支持二维

                    $name = 'is_array($'.$var.')?$'.$var.'["'.$vars[0].'"]:$'.$var.'->'.$vars[0];

            }

        }elseif(strpos($name,':')){

            // 额外的对象方式支持

            $name   =   '$'.str_replace(':','->',$name);

        }elseif(!defined($name)) {

            $name = '$'.$name;

        }

        return $name;

    }



    /**

     * 用于标签属性里面的特殊模板变量解析

     * 格式 以 Think. 打头的变量属于特殊模板变量

     * @access public

     * @param string $varStr  变量字符串

     * @return string

     */

    public function parseThinkVar($varStr){

        if(is_array($varStr)){//用于正则替换回调函数

            $varStr = $varStr[1]; 

        }

        $vars       = explode('.',$varStr);

        $vars[1]    = strtoupper(trim($vars[1]));

        $parseStr   = '';

        if(count($vars)>=3){

            $vars[2] = trim($vars[2]);

            switch($vars[1]){

                case 'SERVER':    $parseStr = '$_SERVER[\''.$vars[2].'\']';break;

                case 'GET':         $parseStr = '$_GET[\''.$vars[2].'\']';break;

                case 'POST':       $parseStr = '$_POST[\''.$vars[2].'\']';break;

                case 'COOKIE':

                    if(isset($vars[3])) {

                        $parseStr = '$_COOKIE[\''.$vars[2].'\'][\''.$vars[3].'\']';

                    }elseif(C('COOKIE_PREFIX')){

                        $parseStr = '$_COOKIE[\''.C('COOKIE_PREFIX').$vars[2].'\']';

                    }else{

                        $parseStr = '$_COOKIE[\''.$vars[2].'\']';

                    }

                    break;

                case 'SESSION':

                    if(isset($vars[3])) {

                        $parseStr = '$_SESSION[\''.$vars[2].'\'][\''.$vars[3].'\']';

                    }elseif(C('SESSION_PREFIX')){

                        $parseStr = '$_SESSION[\''.C('SESSION_PREFIX').'\'][\''.$vars[2].'\']';

                    }else{

                        $parseStr = '$_SESSION[\''.$vars[2].'\']';

                    }

                    break;

                case 'ENV':         $parseStr = '$_ENV[\''.$vars[2].'\']';break;

                case 'REQUEST':  $parseStr = '$_REQUEST[\''.$vars[2].'\']';break;

                case 'CONST':     $parseStr = strtoupper($vars[2]);break;

                case 'LANG':       $parseStr = 'L("'.$vars[2].'")';break;

                case 'CONFIG':    $parseStr = 'C("'.$vars[2].'")';break;

            }

        }else if(count($vars)==2){

            switch($vars[1]){

                case 'NOW':       $parseStr = "date('Y-m-d g:i a',time())";break;

                case 'VERSION':  $parseStr = 'THINK_VERSION';break;

                case 'TEMPLATE':$parseStr = 'C("TEMPLATE_NAME")';break;

                case 'LDELIM':    $parseStr = 'C("TMPL_L_DELIM")';break;

                case 'RDELIM':    $parseStr = 'C("TMPL_R_DELIM")';break;

                default:  if(defined($vars[1])) $parseStr = $vars[1];

            }

        }

        return $parseStr;

    }



    // 获取标签定义

    public function getTags(){

        return $this->tags;

    }

}